package com.bookstore.service.impl;

import com.bookstore.dto.BookDTO;
import com.bookstore.entity.Book;
import com.bookstore.entity.Category;
import com.bookstore.repository.BookRepository;
import com.bookstore.repository.CategoryRepository;
import com.bookstore.service.BookService;
import com.bookstore.service.UserHistoryService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import javax.transaction.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class BookServiceImpl implements BookService {

    @Autowired
    private BookRepository bookRepository;

    @Autowired
    private CategoryRepository categoryRepository;

    @Autowired
    private UserHistoryService userHistoryService;

    @Override
    public List<BookDTO> getAllBooks() {
        return bookRepository.findAll().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public Page<BookDTO> getBooks(Pageable pageable) {
        return bookRepository.findAll(pageable)
                .map(this::convertToDTO);
    }

    @Override
    public BookDTO getBookById(Long id) {
        return bookRepository.findById(id)
                .map(this::convertToDTO)
                .orElseThrow(() -> new RuntimeException("Book not found"));
    }

    @Override
    public BookDTO createBook(BookDTO bookDTO) {
        Book book = convertToEntity(bookDTO);
        book.setCreatedAt(LocalDateTime.now());
        Book savedBook = bookRepository.save(book);
        return convertToDTO(savedBook);
    }

    @Override
    @Transactional
    public BookDTO updateBook(Long id, BookDTO bookDTO) {
        return bookRepository.findById(id)
                .map(book -> {
                    updateBookFromDTO(book, bookDTO);
                    return convertToDTO(bookRepository.save(book));
                })
                .orElseThrow(() -> new RuntimeException("Book not found"));
    }

    @Override
    public void deleteBook(Long id) {
        bookRepository.deleteById(id);
    }

    @Override
    @Deprecated
    public List<BookDTO> searchBooks(Long categoryId, String keyword) {
        // 保持原有实现，但调用新方法
        Page<BookDTO> page = searchBooks(categoryId, keyword, null, null, null, Pageable.unpaged());
        return page.getContent();
    }

    @Override
    public Page<BookDTO> searchBooks(Long categoryId, String keyword, Double minPrice, Double maxPrice, String degree,
            Pageable pageable) {
        // 使用Specification构建动态查询条件
        Specification<Book> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            // 分类条件
            if (categoryId != null) {
                predicates.add(criteriaBuilder.equal(root.get("categoryId"), categoryId));
            }

            // 关键词搜索（标题、作者、描述）
            if (keyword != null && !keyword.isEmpty()) {
                String likePattern = "%" + keyword + "%";
                Predicate titlePredicate = criteriaBuilder.like(root.get("title"), likePattern);
                Predicate authorPredicate = criteriaBuilder.like(root.get("author"), likePattern);
                Predicate descriptionPredicate = criteriaBuilder.like(root.get("description"), likePattern);
                predicates.add(criteriaBuilder.or(titlePredicate, authorPredicate, descriptionPredicate));
            }

            // 价格范围
            if (minPrice != null) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("price"), minPrice));
            }
            if (maxPrice != null) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("price"), maxPrice));
            }

            // 新旧程度
            if (degree != null && !degree.isEmpty()) {
                predicates.add(criteriaBuilder.equal(root.get("degree"), degree));
            }

            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };

        // 执行查询并转换结果
        Page<Book> books = bookRepository.findAll(spec, pageable);
        return books.map(this::convertToDTO);
    }

    private Book convertToEntity(BookDTO dto) {
        Book book = new Book();
        updateBookFromDTO(book, dto);
        if (dto.getCategoryId() != null) {
            Category category = categoryRepository.findById(dto.getCategoryId())
                    .orElseThrow(() -> new RuntimeException("Category not found"));
            book.setCategory(category);
        }
        return book;
    }

    private void updateBookFromDTO(Book book, BookDTO dto) {
        book.setTitle(dto.getTitle());
        book.setAuthor(dto.getAuthor());
        book.setPublisher(dto.getPublisher());
        book.setOriginalPrice(dto.getOriginalPrice());
        book.setPrice(dto.getPrice());
        book.setStatus(dto.getStatus());
        book.setStock(dto.getStock());
        book.setDescription(dto.getDescription());
        book.setImageUrl(dto.getImageUrl());

        // 更新分类
        if (dto.getCategoryId() != null) {
            Category category = categoryRepository.findById(dto.getCategoryId())
                    .orElseThrow(() -> new RuntimeException("Category not found"));
            book.setCategory(category);
        }

        // 更新销量和权重字段
        if (dto.getSalesCount() != null) {
            book.setSalesCount(dto.getSalesCount());
        }
        if (dto.getHotWeight() != null) {
            book.setHotWeight(dto.getHotWeight());
        }
        if (dto.getRecommendWeight() != null) {
            book.setRecommendWeight(dto.getRecommendWeight());
        }
        if (dto.getFlashSaleWeight() != null) {
            book.setFlashSaleWeight(dto.getFlashSaleWeight());
        }

        // 更新新旧程度
        if (dto.getDegree() != null) {
            book.setDegree(dto.getDegree());
        }
    }

    @Override
    public List<BookDTO> getBooksByCategory(Long categoryId) {
        return bookRepository.findByCategoryId(categoryId).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public ResponseEntity<?> addBook(BookDTO bookDTO) {
        try {
            BookDTO createdBook = createBook(bookDTO);
            return ResponseEntity.ok(createdBook);
        } catch (Exception e) {
            return ResponseEntity.badRequest().body("添加图书失败：" + e.getMessage());
        }
    }

    @Override
    public Page<BookDTO> searchBooks(
            Long categoryId,
            String keyword,
            String title,
            String author,
            Double minPrice,
            Double maxPrice,
            String degree,
            Boolean isHot,
            Boolean isRecommended,
            Boolean isFlashSale,
            Pageable pageable) {
        // 使用Specification构建动态查询条件
        Specification<Book> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            // 分类条件
            if (categoryId != null) {
                predicates.add(criteriaBuilder.equal(root.get("category"), categoryId));
            }

            // 关键词搜索（标题、作者、描述）
            if (keyword != null && !keyword.isEmpty()) {
                String likePattern = "%" + keyword + "%";
                Predicate titlePredicate = criteriaBuilder.like(root.get("title"), likePattern);
                Predicate authorPredicate = criteriaBuilder.like(root.get("author"), likePattern);
                Predicate descriptionPredicate = criteriaBuilder.like(root.get("description"), likePattern);
                predicates.add(criteriaBuilder.or(titlePredicate, authorPredicate, descriptionPredicate));
            }

            // 精确书名搜索
            if (title != null && !title.isEmpty()) {
                predicates.add(criteriaBuilder.equal(root.get("title"), title));
            }

            // 精确作者搜索
            if (author != null && !author.isEmpty()) {
                predicates.add(criteriaBuilder.equal(root.get("author"), author));
            }

            // 价格范围
            if (minPrice != null) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("price"), minPrice));
            }
            if (maxPrice != null) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("price"), maxPrice));
            }

            // 新旧程度
            if (degree != null && !degree.isEmpty() && !"all".equals(degree)) {
                predicates.add(criteriaBuilder.equal(root.get("degree"), degree));
            }

            // 热销图书
            if (Boolean.TRUE.equals(isHot)) {
                predicates.add(criteriaBuilder.greaterThan(root.get("hotWeight"), 0));
            }

            // 推荐图书
            if (Boolean.TRUE.equals(isRecommended)) {
                predicates.add(criteriaBuilder.greaterThan(root.get("recommendWeight"), 0));
            }

            // 抢购图书
            if (Boolean.TRUE.equals(isFlashSale)) {
                predicates.add(criteriaBuilder.greaterThan(root.get("flashSaleWeight"), 0));
            }

            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };

        // 执行查询并转换结果
        Page<Book> books = bookRepository.findAll(spec, pageable);
        return books.map(this::convertToDTO);
    }

    @Override
    public Page<BookDTO> getBooksByType(Boolean isHot, Boolean isRecommended, Boolean isFlashSale, Pageable pageable) {
        // 使用Specification构建动态查询条件
        Specification<Book> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            // 热销图书
            if (Boolean.TRUE.equals(isHot)) {
                predicates.add(criteriaBuilder.greaterThan(root.get("hotWeight"), 0));
            }

            // 推荐图书
            if (Boolean.TRUE.equals(isRecommended)) {
                predicates.add(criteriaBuilder.greaterThan(root.get("recommendWeight"), 0));
            }

            // 抢购图书
            if (Boolean.TRUE.equals(isFlashSale)) {
                predicates.add(criteriaBuilder.greaterThan(root.get("flashSaleWeight"), 0));
            }

            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };

        // 执行查询并转换结果
        Page<Book> books = bookRepository.findAll(spec, pageable);
        return books.map(this::convertToDTO);
    }

    public BookDTO convertToDTO(Book book) {
        if (book == null) {
            return null;
        }
        
        BookDTO dto = new BookDTO();
        dto.setId(book.getId());
        dto.setTitle(book.getTitle());
        dto.setAuthor(book.getAuthor());
        dto.setPublisher(book.getPublisher());
        dto.setPrice(book.getPrice());
        dto.setOriginalPrice(book.getOriginalPrice());
        dto.setDescription(book.getDescription());
        dto.setImageUrl(book.getImageUrl());
        dto.setStatus(book.getStatus());
        dto.setStock(book.getStock());
        dto.setSalesCount(book.getSalesCount());
        dto.setHotWeight(book.getHotWeight());
        dto.setRecommendWeight(book.getRecommendWeight());
        dto.setFlashSaleWeight(book.getFlashSaleWeight());
        dto.setDegree(book.getDegree());
        // dto.setCreatedAt(book.getCreatedAt());
        
        // 设置分类相关信息
        if (book.getCategory() != null) {
            dto.setCategoryId(book.getCategory().getId());
            dto.setCategoryName(book.getCategory().getCategoryName());
        }
        
        return dto;
    }

    @Override
    public List<BookDTO> getYouMayLikeBooks(Long userId, Long categoryId, int limit) {
        // 创建分页和排序
        Pageable pageable = PageRequest.of(0, limit, Sort.by(Sort.Direction.DESC, "recommendWeight"));

        // 如果有用户ID，尝试基于用户历史记录推荐
        if (userId != null) {
            // 这里可以调用用户历史记录服务获取用户最近浏览或购买的图书类别
            // 然后基于这些类别推荐相似的图书

            // 假设我们有一个方法可以获取用户最近感兴趣的类别ID列表
            List<Long> userInterestedCategories = getUserInterestedCategories(userId);

            if (!userInterestedCategories.isEmpty()) {
                // 基于用户感兴趣的类别推荐图书
                return bookRepository.findByCategoryIdIn(userInterestedCategories, pageable)
                        .stream()
                        .map(this::convertToDTO)
                        .collect(Collectors.toList());
            }
        }

        // 如果提供了特定类别，则推荐该类别的图书
        if (categoryId != null) {
            return bookRepository.findByCategoryId(categoryId, pageable)
                    .stream()
                    .map(this::convertToDTO)
                    .collect(Collectors.toList());
        }

        // 如果没有用户ID或类别ID，或者无法获取用户兴趣，则返回一般推荐
        // 这里我们使用推荐权重高的图书，也可以随机选择
        return bookRepository.findAll(pageable)
                .stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    // 修改现有方法
    
    // 辅助方法：获取用户感兴趣的类别
    private List<Long> getUserInterestedCategories(Long userId) {
        // 调用用户历史记录服务获取用户感兴趣的类别
        return userHistoryService.getUserInterestedCategories(userId);
    }
}